package com.adouteam.simple.wechat.service;

import com.adouteam.simple.wechat.base.Constant;
import com.adouteam.simple.wechat.base.WechatConstants;
import com.adouteam.simple.wechat.base.WeixinUrls;
import com.adouteam.simple.wechat.bean.JsApiSignature;
import com.adouteam.simple.wechat.bean.JsApiTicket;
import com.adouteam.simple.wechat.tool.Encrypt;
import com.adouteam.simple.wechat.tool.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * JsApi相关服务类
 */
public class JsApiService {
    private static final Logger logger = LoggerFactory.getLogger(JsApiService.class);

    private static final int NONCE_LENGTH = 16;
    private static final String PARAMS_SEPARATOR = "&";
    private static final String ANCHOR_SEPARATOR = "#";
    private static final String PARAM_KEY_VALUE_SEPARATOR = "=";

    private static final String TIMESTAMP_KEY = "timestamp";
    private static final String JS_API_TICKET_KEY = "jsapi_ticket";
    private static final String URL_KEY = "url";
    private static final String NONCE_STR_KEY = "noncestr";

    private static final String[] PARAM_KEYS = new String[]{TIMESTAMP_KEY, JS_API_TICKET_KEY, URL_KEY, NONCE_STR_KEY};

    public static JsApiSignature fetchJsApiSignature(String url, WechatConstants wechatConstants) {
        if (StringUtils.contains(url, ANCHOR_SEPARATOR)) {
            url = StringUtils.substringBefore(url, ANCHOR_SEPARATOR);
        }
        Long timestamp = System.currentTimeMillis() / 1000L;
        String nonceStr = RandomStringUtils.randomAlphanumeric(NONCE_LENGTH);
        String jsApiTicket = getJsApiTicket(wechatConstants);
        String signature = createJsApiSignature(timestamp, nonceStr, jsApiTicket, url);
        JsApiSignature jsApiSignature = new JsApiSignature(wechatConstants.getAppId(), url, nonceStr, timestamp, signature);
        return jsApiSignature;
    }

    /**
     * 辅助生成合法的url
     *
     * @param request         请求
     * @param wechatConstants 微信配置参数
     * @return url地址
     */
    public static String helpToBuildUrl(HttpServletRequest request, WechatConstants wechatConstants) {
        StringBuilder url = new StringBuilder();
        url.append(wechatConstants.getDomainName().substring(0, wechatConstants.getDomainName().length() - 1));
        url.append(request.getRequestURI());
        if (StringUtils.isBlank(request.getQueryString()) || StringUtils.startsWith(request.getQueryString(), ANCHOR_SEPARATOR)) {
            return url.toString();
        }
        url.append("?");
        url.append(StringUtils.substringBefore(request.getQueryString(), "#"));
        return url.toString();
    }

    /**
     * 签名逻辑
     *
     * @param timestamp   时间戳
     * @param nonceStr    nonceStr
     * @param jsApiTicket JsApi票据
     * @param url         签名地址
     * @return 签名值
     */
    protected static String createJsApiSignature(long timestamp, String nonceStr, String jsApiTicket, String url) {
        Map<String, Object> params = new HashMap<>();
        params.put(TIMESTAMP_KEY, timestamp);
        params.put(NONCE_STR_KEY, nonceStr);
        params.put(JS_API_TICKET_KEY, jsApiTicket);
        params.put(URL_KEY, url);
        Arrays.sort(PARAM_KEYS);

        StringBuilder sb = new StringBuilder();
        for (String paramKey : PARAM_KEYS) {
            if (StringUtils.isNotBlank(sb)) {
                sb.append(PARAMS_SEPARATOR);
            }
            sb.append(paramKey);
            sb.append(PARAM_KEY_VALUE_SEPARATOR);
            sb.append(params.get(paramKey));
        }

        return Encrypt.encryptSHA1(sb.toString());
    }

    /**
     * 刷新JsApiTicket
     *
     * @param wechatConstants 微信配置参数
     * @return 签名值
     */
    public static String getJsApiTicket(WechatConstants wechatConstants) {
        return forceGetJsApiTicket(wechatConstants);
    }

    /**
     * 直接请求JsApiTicket
     *
     * @param wechatConstants 微信配置参数
     * @return 签名值
     */
    private static String forceGetJsApiTicket(WechatConstants wechatConstants) {
        String url = WeixinUrls.replace(WeixinUrls.JS_SDK_GET_TICKET_URL, wechatConstants, null);
        return HttpUtil.get(url, null, (httpResponse -> {
            String responseContent = EntityUtils.toString(httpResponse.getEntity(), Charset.forName("utf-8"));
            if (StringUtils.isBlank(responseContent)) {
                return null;
            }
            JsApiTicket jsApiTicket = JSONObject.parseObject(responseContent, JsApiTicket.class);
            if (null == jsApiTicket || StringUtils.isBlank(jsApiTicket.getTicket())) {
                return null;
            }
            logger.info(Constant.LOGGER_PREFIX + "jsApiTicket:" + jsApiTicket);
            return jsApiTicket.getTicket();
        }));
    }
}
